﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;


namespace serwer {
    /// <summary>
    /// Interpretuje tekstowe polecenia, wykonuje operacje na serwerze i zwraca rezultat.
    /// </summary>
    class CommandInterpreter {
        /// <summary>
        /// Serwer, na którym wykonywane są operacje.
        /// </summary>
        private readonly Server server;

        /// <summary>
        /// Tworzy instancję obiektu interpretującego tekstowe polecenia dla serwera.
        /// </summary>
        /// <param name="server">Serwer, na którym wykonywane będą operacje.</param>
        public CommandInterpreter(Server server) {
            this.server = server;
        }
        /// <summary>
        /// Wykonuje operację na serwerze na podstawie podanego polecenia tekstowego.
        /// </summary>
        /// <param name="command">Polecenie do wykonania w formie tekstowej.</param>
        /// <returns>Odpowiedź serwera na polecenie.</returns>
        public string ExecuteCommand(string command) {
            try {
                string lowercaseCommand = command.ToLower();
                if (lowercaseCommand == "start") {
                    return CmdStart();
                }
                else if (lowercaseCommand == "stop") {
                    return CmdStop();
                }
                else if (lowercaseCommand == "list") {
                    return CmdList();
                }
                else if (lowercaseCommand == "help") {
                    return CmdHelp();
                }
                else if (lowercaseCommand == "exit") {
                    return null;
                }
                else if (lowercaseCommand.StartsWith("disconnect ")) {
                    string param = lowercaseCommand.Substring(11);
                    return CmdDisconnect(param);
                }
                else return CmdUnknown();
            }
            catch (Exception ex) {
                throw ex;
            }
        }

        /// <summary>
        /// Rozpoczyna nasłuchiwanie.
        /// </summary>
        /// <returns>Odpowiedź na polecenie.</returns>
        private string CmdStart() {
            try {
                if (server.Start()) return "Serwer został uruchomiony.";
                else return "Serwer jest już uruchomiony.";
            }
            catch (Exception ex) {
                return ex.Message;
            }
        }
        /// <summary>
        /// Zatrzymuje nasłuchiwanie i rozłącza wszystkich klientów.
        /// </summary>
        /// <returns>Odpowiedź na polecenie.</returns>
        private string CmdStop() {
            if (server.Stop()) return "Serwer został zatrzymany.";
            else return "Serwer jest już zatrzymany.";
        }
        /// <summary>
        /// Pobiera listę podłączonych klientów.
        /// </summary>
        /// <returns>Lista podłączonych klientów w formie tekstowej.</returns>
        private string CmdList() {
            if (!server.IsListening) return "Serwer jest zatrzymany.";
            List<ClientInformation> clientInformation = server.GetClientList(ClientListOrder.IdAscending);
            StringBuilder builder = new StringBuilder();
            string div =       "#--------------------------------------#";
            builder.AppendLine(div);
            builder.AppendLine("|          Połączeni klienci:          |");
            builder.AppendLine(div);
            builder.AppendLine("|    ID    |   Adres IP    |    Czas   |");
            builder.AppendLine(div);
                foreach (ClientInformation c in clientInformation) {
                    builder.AppendLine(String.Format("|{0,10}|{1,15}|{2,11}|",
                                                        c.ClientID,
                                                        c.ClientIP,
                                                        c.ConnectionTime));
                }
            builder.AppendLine(div);
            return builder.ToString();
        }
        /// <summary>
        /// Rozłącza wybranego klienta.
        /// </summary>
        /// <param name="client">Adres IP lub identyfikator klienta do rozłączenia.</param>
        /// <returns>Odpowiedź na polecenie.</returns>
        private string CmdDisconnect(string client) {
            string ipRegex = @"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
            string idRegex = @"^([1-9][0-9]*)$";
            bool disconnected = false;
            if (System.Text.RegularExpressions.Regex.IsMatch(client, ipRegex)) {
                if (server.DisconnectClient(client)) {
                    disconnected = true;
                }
                else disconnected = false;
            }
            else if (System.Text.RegularExpressions.Regex.IsMatch(client, idRegex)) {
                if (server.DisconnectClient(Int32.Parse(client))) {
                    disconnected = true;
                }
                else disconnected = false;
            }
            else return "Niewłaściwy parametr. Podaj poprawny adres IP lub identyfikator.";
            if (disconnected) return "Klient został pomyślnie rozłączony.";
            else return "Klient o podanym adresie IP lub identyfikatorze nie istnieje.";
        }
        /// <summary>
        /// Zwraca listę dostępnych poleceń i ich składni w formie tekstowej.
        /// </summary>
        /// <returns>Lista i składnia dostępnych poleceń.</returns>
        private string CmdHelp() {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(@"Dostępne polecenia:");
            sb.AppendLine(@"                 start - uruchamia nasłuchiwanie");
            sb.AppendLine(@"                  stop - zatrzymuje nasłuchiwanie");
            sb.AppendLine(@"                  list - wyświetla listę połączonych klientów");
            sb.AppendLine(@"    disconnect {param} - rozłącza wybranego klienta");
            sb.AppendLine(@"        param - ID lub adres IP klienta do rozłączenia");
            sb.AppendLine(@"                  help - wyświetla dostępne polecenia");
            sb.AppendLine(@"                  exit - kończy działanie programu");
            return sb.ToString();
        }
        /// <summary>
        /// Informuje o niewłaściwym poleceniu lub jego składni.
        /// </summary>
        /// <returns>Informacja o niewłaściwej nazwie polecenia.</returns>
        private string CmdUnknown() {
            return "Niewłaściwe polecenie. \nUżyj polecenia help aby uzyskać listę poleceń i ich składnię.";
        }
        /// <summary>
        /// Kończy pracę programu.
        /// </summary>
        private void CmdExit() {
            server.Stop();
            throw new Exception("Wpisano polecenie Exit");
        }        
    }
}
